package com.campuscarbooking.api.service.impl;

import com.campuscarbooking.api.dto.UserDTO;
import com.campuscarbooking.api.dto.auth.LoginResponse;
import com.campuscarbooking.api.dto.auth.PhoneLoginRequest;
import com.campuscarbooking.api.dto.auth.WechatLoginRequest;
import com.campuscarbooking.api.exception.AuthenticationException;
import com.campuscarbooking.api.model.User;
import com.campuscarbooking.api.repository.UserRepository;
import com.campuscarbooking.api.security.JwtTokenProvider;
import com.campuscarbooking.api.service.AuthService;
import com.campuscarbooking.api.service.WechatService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
@Slf4j
public class AuthServiceImpl implements AuthService {

    private final UserRepository userRepository;
    private final JwtTokenProvider jwtTokenProvider;
    private final WechatService wechatService;
    private final RedisTemplate<String, String> redisTemplate;

    private static final String VERIFICATION_CODE_PREFIX = "verification_code:";
    private static final int VERIFICATION_CODE_EXPIRE_MINUTES = 5;

    @Override
    @Transactional
    public LoginResponse wechatLogin(WechatLoginRequest request) throws AuthenticationException {
        // 调用微信API获取openid
        String openid = wechatService.getOpenidByCode(request.getCode());
        if (openid == null) {
            throw new AuthenticationException("微信授权失败");
        }

        // 查找或创建用户
        User user = findOrCreateWechatUser(openid, request.getUserType());

        // 生成JWT令牌
        String token = generateToken(user);

        // 构建响应
        LoginResponse response = new LoginResponse();
        response.setToken(token);
        response.setUser(UserDTO.fromEntity(user));

        return response;
    }

    @Override
    @Transactional
    public LoginResponse phoneLogin(PhoneLoginRequest request) throws AuthenticationException {
        // 查找用户
        Optional<User> userOpt = userRepository.findByPhone(request.getPhone());
        User user;

        // 根据登录类型选择不同的验证方式
        if ("password".equals(request.getLoginType())) {
            // 密码登录
            if (request.getPassword() == null || request.getPassword().isEmpty()) {
                throw new AuthenticationException(40002, "密码不能为空");
            }
            
            // 密码登录必须确保用户存在
            if (userOpt.isEmpty()) {
                throw new AuthenticationException(40001, "用户不存在");
            }
            user = userOpt.get();
            
            // 校验密码（明文比对，生产环境应加密）
            if (user.getPassword() == null || !user.getPassword().equals(request.getPassword())) {
                throw new AuthenticationException(40002, "密码错误");
            }
        } else if ("code".equals(request.getLoginType())) {
            // 验证码登录
            if (request.getCode() == null || request.getCode().isEmpty()) {
                throw new AuthenticationException(40002, "验证码不能为空");
            }
            // 验证码校验
            boolean isCodeValid = validateSmsCode(request.getPhone(), request.getCode());
            if (!isCodeValid) {
                throw new AuthenticationException(40002, "验证码错误");
            }
            
            // 如果是验证码登录且用户不存在，则创建新用户
            if (userOpt.isPresent()) {
                user = userOpt.get();
            } else {
                user = findOrCreatePhoneUser(request.getPhone(), request.getUserType());
            }
        } else {
            throw new AuthenticationException(40004, "不支持的登录类型");
        }

        // 校验用户类型
        if (!user.getUserType().name().equalsIgnoreCase(request.getUserType())) {
            throw new AuthenticationException(40003, "用户类型不匹配");
        }
        
        // 生成JWT令牌
        String token = generateToken(user);
        
        // 构建响应
        LoginResponse response = new LoginResponse();
        response.setToken(token);
        response.setUser(UserDTO.fromEntity(user));
        return response;
    }

    @Override
    public void sendVerificationCode(String phoneNumber) {
        // Generate a random 6-digit code
        String code = String.format("%06d", new Random().nextInt(999999));

        // In a real app, send the code via SMS. For now, just log it
        log.info("Send verification code: {} to phone: {}", code, phoneNumber);

        // Store the code in Redis with an expiration time
        String key = VERIFICATION_CODE_PREFIX + phoneNumber;
        redisTemplate.opsForValue().set(key, code, VERIFICATION_CODE_EXPIRE_MINUTES, TimeUnit.MINUTES);
    }

    private User findOrCreateWechatUser(String openid, String userType) {
        Optional<User> existingUser = userRepository.findByWxOpenid(openid);

        if (existingUser.isPresent()) {
            return existingUser.get();
        } else {
            User newUser = new User();
            newUser.setWxOpenid(openid);
            newUser.setUserType(User.UserType.valueOf(userType));
            return userRepository.save(newUser);
        }
    }

    private User findOrCreatePhoneUser(String phone, String userType) {
        Optional<User> existingUser = userRepository.findByPhone(phone);

        if (existingUser.isPresent()) {
            return existingUser.get();
        } else {
            User newUser = new User();
            newUser.setPhone(phone);
            newUser.setUserType(User.UserType.valueOf(userType));
            return userRepository.save(newUser);
        }
    }

    private boolean validateSmsCode(String phone, String code) {
        // 从Redis中获取验证码
        String key = VERIFICATION_CODE_PREFIX + phone;
        String storedCode = redisTemplate.opsForValue().get(key);
        
        // 验证码校验
        if (storedCode != null && storedCode.equals(code)) {
            // 验证成功后删除验证码
            redisTemplate.delete(key);
            return true;
        }
        
        // 开发模式下，如果Redis中没有验证码，使用固定验证码123456进行测试
        return "123456".equals(code);
    }

    private String generateToken(User user) {
        String role = "ROLE_USER";
        if (user.getUserType() == User.UserType.teacher) {
            role = "ROLE_TEACHER";
        }

        List<SimpleGrantedAuthority> authorities = Collections.singletonList(
            new SimpleGrantedAuthority(role)
        );

        return jwtTokenProvider.createToken(user.getId().toString(), authorities);
    }
} 